home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 050 / madtrb10.arc / TREE.INC < prev    next >
Encoding:
Text File  |  1985-12-05  |  52.5 KB  |  1,285 lines

  1. Procedure PrintHeading;
  2.  
  3. { This procedure prints a heading for the program. }
  4.  
  5. Begin   { PrintHeading }
  6.   WriteLn;
  7.   WriteLn;
  8.   WriteLn('MAIL ORDER PROCESSING DEMONSTRATION PROGRAM');
  9.   WriteLn('-------------------------------------------');
  10.   WriteLn;
  11. End;    { PrintHeading }
  12.  
  13.  
  14.  
  15. Procedure InitPointers;
  16.  
  17. { This procedure initializes the global pointers used in this program to Nil. }
  18.  
  19. Begin   { InitPointers }
  20.   NewItemHeadPtr:=Nil;
  21.   NewItemTailPtr:=Nil;
  22.   AddQuantityHeadPtr:=Nil;
  23.   AddQuantityTailPtr:=Nil;
  24.   SellQuantityHeadPtr:=Nil;
  25.   SellQuantityTailPtr:=Nil;
  26.   RemoveItemHeadPtr:=Nil;
  27.   RemoveItemTailPtr:=Nil;
  28.   CurrentEmployeePtr:=Nil;
  29.   TreeRootPtr:=Nil;
  30. End;    { InitPointers }
  31.  
  32.  
  33.  
  34. Procedure RemoveFirstEntryFromString(Var Text:FileEntryString);
  35.  
  36. { This procedure removes the first text entry from the passed text string and
  37.   returns the new truncated text string.  The text entries in the passed text
  38.   string are assumed to be delinated by one space.  See the following
  39.   example.
  40.  
  41.          Passed:    Entry1  Entry2  Entry3
  42.          Returned:  Entry2  Entry3                      }
  43.  
  44. Begin   { RemoveFirstEntryFromString }
  45.   If Pos(' ',Text)<>0 Then
  46.     Text:=Copy(Text,(Pos(' ',Text)+1),(Length(Text)-Pos(' ',Text)));
  47. End;    { RemoveFirstEntryFromString }
  48.  
  49.  
  50.  
  51. Procedure ReturnFirstEntryFromString(Var Text:FileEntryString);
  52.  
  53. { This procedure removes the first text entry from the passed text string and
  54.   returns the first text entry.  The text entries in the passed text string
  55.   are assumed to be delinated by one space.  See the following example.
  56.  
  57.          Passed:    Entry1  Entry2  Entry3
  58.          Returned:  Entry1                              }
  59.  
  60. Begin   { ReturnFirstEntryFromString }
  61.   If Pos(' ',Text)<>0 Then
  62.     Text:=Copy(Text,1,(Pos(' ',Text)-1));
  63. End;    { ReturnFirstEntryFromString }
  64.  
  65.  
  66.  
  67. Function TransactionCode(Entry:FileEntryString):EntryString;
  68.  
  69. { This function is passed a file entry which contains a transaction code as the
  70.   first entry.  This function picks off the transaction code from the file
  71.   entry and passes the transaction code back. }
  72.  
  73. Begin   { TransactionCode }
  74.   ReturnFirstEntryFromString(Entry);
  75.   TransactionCode:=Entry;
  76. End;    { TransactionCode }
  77.  
  78.  
  79.  
  80. Function ReturnSecondEntry(FileEntry:FileEntryString):EntryString;
  81.  
  82. { This function is passed a file entry which contains entries seperated by a
  83.   blank space.  This function picks off the second entry from the file entry
  84.   and passes the second entry back. }
  85.  
  86. Begin   { ReturnSecondEntry }
  87.   RemoveFirstEntryFromString(FileEntry);
  88.   ReturnFirstEntryFromString(FileEntry);
  89.   ReturnSecondEntry:=FileEntry;
  90. End;    { ReturnSecondEntry }
  91.  
  92.  
  93.  
  94. Function ReturnThirdEntry(FileEntry:FileEntryString):EntryString;
  95.  
  96. { This function is passed a file entry which contains entries seperated by a
  97.   blank space.  This function picks off the third entry from the file entry and
  98.   passes the third entry back. }
  99.  
  100. Begin   { ReturnThirdEntry }
  101.   RemoveFirstEntryFromString(FileEntry);
  102.   RemoveFirstEntryFromString(FileEntry);
  103.   ReturnFirstEntryFromString(FileEntry);
  104.   ReturnThirdEntry:=FileEntry;
  105. End;    { ReturnThirdEntry }
  106.  
  107.  
  108.  
  109. Procedure PrintQueues;
  110.  
  111. { This procedure is used to print out the contents of the four transaction
  112.   queues. }
  113.  
  114. Var
  115.   TempQueueElementPtr:QueueElementPtr; { a temporary pointer used in traversing the queues }
  116.  
  117. Begin   { PrintQueues }
  118.   WriteLn;
  119.   WriteLn;
  120.   WriteLn('ITEMS LEFT ON TRANSACTION QUEUES :');
  121.   WriteLn;
  122.   WriteLn('     New Items Queue follows:');
  123.   WriteLn;
  124.   If NewItemHeadPtr=Nil Then
  125.       WriteLn('          No items on queue.')
  126.   Else
  127.     Begin
  128.       TempQueueElementPtr:=NewItemHeadPtr;
  129.       While TempQueueElementPtr<>Nil Do
  130.         Begin
  131.           WriteLn('          Item Name : ',TempQueueElementPtr^.ItemName,
  132.                   '   Quantity : ',TempQueueElementPtr^.ItemQuantity);
  133.           TempQueueElementPtr:=TempQueueElementPtr^.Back; { increment queue pointer }
  134.         End; { While TempQueueElementPtr }
  135.     End; { Else }
  136.   WriteLn;
  137.   WriteLn;
  138.   WriteLn('     Added Quantity Items Queue follows:');
  139.   WriteLn;
  140.   If AddQuantityHeadPtr=Nil Then
  141.       WriteLn('          No items on queue.')
  142.   Else
  143.     Begin
  144.       TempQueueElementPtr:=AddQuantityHeadPtr;
  145.       While TempQueueElementPtr<>Nil Do
  146.         Begin
  147.           WriteLn('          Item Name : ',TempQueueElementPtr^.ItemName,
  148.                   '   Quantity : ',TempQueueElementPtr^.ItemQuantity);
  149.           TempQueueElementPtr:=TempQueueElementPtr^.Back; { increment queue pointer }
  150.         End; { While TempQueueElementPtr }
  151.     End; { Else }
  152.   WriteLn;
  153.   WriteLn;
  154.   WriteLn('     Sell Items Queue follows:');
  155.   WriteLn;
  156.   If SellQuantityHeadPtr=Nil Then
  157.       WriteLn('          No items on queue.')
  158.   Else
  159.     Begin
  160.       TempQueueElementPtr:=SellQuantityHeadPtr;
  161.       While TempQueueElementPtr<>Nil Do
  162.         Begin
  163.           WriteLn('          Item Name : ',TempQueueElementPtr^.ItemName,
  164.                   '   Quantity : ',TempQueueElementPtr^.ItemQuantity);
  165.           TempQueueElementPtr:=TempQueueElementPtr^.Back; { increment queue pointer }
  166.         End; { While TempQueueElementPtr }
  167.     End; { Else }
  168.   WriteLn;
  169.   WriteLn;
  170.   WriteLn('     Remove Items Queue follows:');
  171.   WriteLn;
  172.   If RemoveItemHeadPtr=Nil Then
  173.       WriteLn('          No items on queue.')
  174.   Else
  175.     Begin
  176.       TempQueueElementPtr:=RemoveItemHeadPtr;
  177.       While TempQueueElementPtr<>Nil Do
  178.         Begin
  179.           WriteLn('          Item Name : ',TempQueueElementPtr^.ItemName);
  180.           TempQueueElementPtr:=TempQueueElementPtr^.Back; { increment queue pointer }
  181.         End; { While TempQueueElementPtr }
  182.     End; { Else }
  183.   WriteLn;
  184.   WriteLn('END OF DAY');
  185.   WriteLn('----------');
  186.   WriteLn;
  187.   WriteLn;
  188. End;    { PrintQueues }
  189.  
  190.  
  191.  
  192. Procedure PrintEmployeeQueue;
  193.  
  194. { This procedure is used to print out the contents of the doubly linked
  195.   circular employee queue. }
  196.  
  197. Var
  198.   TempQueueElementPtr:EmployeePtr;     { a temporary pointer used in traversing the queue }
  199.  
  200. Begin   { PrintEmployeeQueue }
  201.   WriteLn;
  202.   WriteLn;
  203.   WriteLn('LIST OF CURRENT MAIL ORDER CLERKS :');
  204.   WriteLn;
  205.   If CurrentEmployeePtr=Nil Then
  206.     WriteLn('     No Employees In Employee Queue')
  207.   Else
  208.     Begin
  209.       TempQueueElementPtr:=CurrentEmployeePtr;
  210.       Repeat;
  211.         WriteLn('     ',TempQueueElementPtr^.EmployeeName);
  212.         TempQueueElementPtr:=TempQueueElementPtr^.NextEmployee;
  213.       Until TempQueueElementPtr=CurrentEmployeePtr;
  214.     End; { Else }
  215. End;    { PrintEmployeeQueue }
  216.  
  217.  
  218.  
  219. Procedure AddElementToQueue(Var HeadPtr,TailPtr:QueueElementPtr;FileEntry:FileEntryString);
  220.  
  221. { This procedure adds a queue element to the end of the passed tail pointer
  222.   of a particular doubly linked transaction queue.   There are four transaction
  223.   queues which correspond to:
  224.  
  225.               Insert a new item into the store's inventory.
  226.               Add a quantity to an existing item.
  227.               Sell a quantity of an existing item.
  228.               Remove an item from the store's inventory.
  229.  
  230.   By adding the queue element to the end of the passed tail pointer, this
  231.   maintains first in/first out (FIFO) order.
  232.  
  233.   Note that there are two special cases when inserting a queue element into a
  234.   particular transaction queue:
  235.  
  236.               1. Empty transaction queue.
  237.               2. Transaction queue present.          }
  238.  
  239. Var
  240.   NewQueueElement:QueueElementPtr; { a pointer to a new queue element which will be added to the tail
  241.                                          of the passed transaction queue }
  242.  
  243. Begin   { AddElementToQueue }
  244.   New(NewQueueElement);                { create a new queue element to add to the end of the passed queue }
  245.   With NewQueueElement^ Do
  246.     Begin                              { routine to enter information into the new queue element }
  247.       ItemName:=ReturnSecondEntry(FileEntry);
  248.       ItemQuantity:=ReturnThirdEntry(FileEntry);
  249.       Front:=Nil;                      { set forward pointer to Nil }
  250.       Back:=Nil;                       { set backward pointer to Nil }
  251.     End; { With NewQueueElement }
  252.   { Special Case One - Check for existance of transaction queue }
  253.   If HeadPtr=Nil Then
  254.     Begin
  255.       HeadPtr:=NewQueueElement;        { set particular queue head pointer to point to the first element in the queue }
  256.       TailPtr:=NewQueueElement;        { set particular queue tail pointer to point to the first element in the queue }
  257.     End { If HeadPtr }
  258.   Else
  259.     { Special Case Two - existant transaction queue }
  260.     Begin
  261.       TailPtr^.Back:=NewQueueElement;  { link new queue element to end of the transaction queue }
  262.       NewQueueElement^.Front:=TailPtr; { link new queue element to end of the transaction queue }
  263.       TailPtr:=NewQueueElement;        { increment tail pointer }
  264.     End; { Else }
  265. End;    { AddElementToQueue }
  266.  
  267.  
  268.  
  269. Procedure ProcessEmployeeModule(FileEntry:FileEntryString);
  270.  
  271. { This module controls the hiring and quiting of mail order clerks.
  272.  
  273.   To facilitate insertions and deletions of mail order clerks into the
  274.   employee pool, a doubly linked circular queue is used.
  275.  
  276.   If a new clerk is added to the queue with the HIRE command, he/she is added
  277.   to the spot behind the current employee, i.e. added to the end of the
  278.   current cycle to have time to learn the system.
  279.  
  280.   When clerks quit their job, they are removed from the circular queue.  If the
  281.   current employee happens to be the clerk that quit, the current employee is
  282.   then moved forward to the next clerk in the queue.  The current employee is
  283.   the current mail order clerk that is processing transactions. }
  284.  
  285. Var
  286.   Command:EntryString;                 { a string used to store the employee processing command }
  287.   Name:EntryString;                    { a string used to store the employee name }
  288.  
  289.  
  290.  
  291.   Function EmployeeExist(Name:ClerkString):Boolean;
  292.  
  293.   { This function determines if the passed name is a name of an employee that
  294.     already works for the store.  If the passed name exists then this function
  295.     returns as true, else it returns as false. }
  296.  
  297.   Var
  298.     TempEmployeePtr:EmployeePtr;       { a temporary pointer used in searching for an employee already
  299.                                          existant in the employee queue }
  300.     Found:Boolean;                     { a flag used in detecting if the employee was successfully deleted
  301.                                          from the queue }
  302.  
  303.   Begin   { EmployeeExist }
  304.     Found:=False;
  305.     TempEmployeePtr:=CurrentEmployeePtr;
  306.     If TempEmployeePtr<>Nil Then
  307.       Repeat { search routine }
  308.         If TempEmployeePtr^.EmployeeName=Name Then
  309.           Found:=True
  310.         Else
  311.           TempEmployeePtr:=TempEmployeePtr^.NextEmployee;
  312.       Until (TempEmployeePtr=CurrentEmployeePtr) Or Found;
  313.     EmployeeExist:=Found; { pass back result of search }
  314.   End;    { EmployeeExist }
  315.  
  316.  
  317.  
  318.   Procedure HireEmployee(Name:ClerkString);
  319.  
  320.   { This procedure inserts the newly hired employee into the employee pool,
  321.     which is represented by a doubly linked circular list.
  322.  
  323.     There are two special cases when trying to insert an employee into the
  324.     doubly linked circular queue:
  325.  
  326.            1. If no employees are yet present in the queue, the newly hired
  327.               employee becomes the current employee.
  328.  
  329.            2. The newly hired employee already exists in the employee queue.
  330.               Ignore this hire command.
  331.  
  332.            3. Otherwise, the new clerk is added to the queue at the spot behind
  333.               the current employee, i.e. added to the end of the current cycle
  334.               to have time to learn the system. }
  335.  
  336.   Var
  337.     NewEmployee:EmployeePtr;           { a pointer to the newly hired employee }
  338.  
  339.   Begin   { HireEmployee }
  340.     If Not EmployeeExist(Name) Then
  341.       Begin { new employee }
  342.         New(NewEmployee);                  { create a new employee queue element to add to the queue }
  343.         With NewEmployee^ Do
  344.           Begin
  345.             EmployeeName:=Name;
  346.             ItemsProcessedDuringShift:=0;
  347.             If CurrentEmployeePtr=Nil Then
  348.               Begin
  349.                 { No employees yet present in the queue }
  350.                 NextEmployee:=NewEmployee; { next employee in the queue is itself }
  351.                 LastEmployee:=NewEmployee; { last employee in the queue is itself }
  352.                 CurrentEmployeePtr:=NewEmployee; { newly hired employee becomes the current employee }
  353.               End { If CurrentEmployeePtr }
  354.             Else
  355.               Begin
  356.                 { Queue is present, link new employee into queue just behind current employee }
  357.                 NextEmployee:=CurrentEmployeePtr;
  358.                 LastEmployee:=CurrentEmployeePtr^.LastEmployee;
  359.                 CurrentEmployeePtr^.LastEmployee^.NextEmployee:=NewEmployee; { relink queue }
  360.                 CurrentEmployeePtr^.LastEmployee:=NewEmployee; { relink queue }
  361.               End; { Else }
  362.             WriteLn;
  363.             WriteLn('The newly hired employee ',EmployeeName,' was inserted into the employee queue.');
  364.           End; { With NewEmployee }
  365.       End { If Not EmployeeExist }
  366.     Else { new employee already exists in the employee pool }
  367.       Begin
  368.         WriteLn;
  369.         WriteLn('The already existant employee ',Name,' somehow was placed');
  370.         WriteLn('in the transaction file as a new emploee that was hired.  The');
  371.         WriteLn('false transaction has been ignored.');
  372.       End; { Else }
  373.   End;    { HireEmployee }
  374.  
  375.  
  376.  
  377.   Procedure EmployeeQuit(Var Name:ClerkString);
  378.  
  379.   { This procedure deletes the employee from the employee pool who has just
  380.     quit.
  381.  
  382.     There are four special cases when trying to delete an employee from the
  383.     doubly linked circular queue:
  384.  
  385.            1. If the clerk that quit was the last element in the queue, then
  386.               the current employee pointer is then set to nil.
  387.  
  388.            2. If the current employee happens to be the clerk that quit, the
  389.               current employee is then moved forward to the next clerk in the
  390.               queue.
  391.  
  392.            3. If the clerk that quit is not the current employee then the queue
  393.               is traversed until the proper element is found and deleted.
  394.  
  395.            4. The clerk that quit was never in the queue. }
  396.  
  397.   Var
  398.     Found:Boolean;                     { a flag used in detecting if the employee was successfully deleted
  399.                                          from the queue }
  400.     TempEmployeePtr:EmployeePtr;       { a temporary pointer used in deleting a employee
  401.                                          from the queue }
  402.  
  403.   Begin   { EmployeeQuit }
  404.     Found:=False;                      { initialize flag }
  405.     If CurrentEmployeePtr<>Nil Then
  406.       Begin
  407.         { Special Case One - Check if clerk is last element in queue }
  408.         If (Name=CurrentEmployeePtr^.EmployeeName) And (CurrentEmployeePtr^.NextEmployee=CurrentEmployeePtr) Then
  409.           Begin { Delete last remaining employee from queue }
  410.             Dispose(CurrentEmployeePtr);
  411.             CurrentEmployeePtr:=Nil;
  412.             Found:=True; { set flag }
  413.           End { If Name }
  414.         Else
  415.           { Special Case Two - Check if clerk is current employee }
  416.           If Name=CurrentEmployeePtr^.EmployeeName Then
  417.             Begin { delete current employee from queue }
  418.               TempEmployeePtr:=CurrentEmployeePtr; { temporarily store employee for deleting later }
  419.               CurrentEmployeePtr^.NextEmployee^.LastEmployee:=CurrentEmployeePtr^.LastEmployee; { relink queue }
  420.               CurrentEmployeePtr^.LastEmployee^.NextEmployee:=CurrentEmployeePtr^.NextEmployee; { relink queue }
  421.               CurrentEmployeePtr:=CurrentEmployeePtr^.NextEmployee; { increment  current employee pointer to point
  422.                                                                       to next employee in the queue }
  423.               Dispose(TempEmployeePtr);
  424.               Found:=True; { set flag }
  425.             End { If Name }
  426.           Else
  427.             { Special Case Three - Try to find clerk to delete in the circular queue }
  428.             Begin
  429.               TempEmployeePtr:=CurrentEmployeePtr^.NextEmployee;
  430.               While (TempEmployeePtr<>CurrentEmployeePtr) And Not Found Do
  431.                 Begin
  432.                   If TempEmployeePtr^.EmployeeName=Name Then
  433.                     Begin { delete employee from queue }
  434.                       TempEmployeePtr^.NextEmployee^.LastEmployee:=TempEmployeePtr^.LastEmployee; { relink queue }
  435.                       TempEmployeePtr^.LastEmployee^.NextEmployee:=TempEmployeePtr^.NextEmployee; { relink queue }
  436.                       Dispose(TempEmployeePtr);
  437.                       Found:=True; { set flag }
  438.                     End { If TempEmployeePtr }
  439.                   Else
  440.                     TempEmployeePtr:=TempEmployeePtr^.NextEmployee; { incrementQueue pointer }
  441.                 End; { While TempEmployeePtr }
  442.             End; { Else }
  443.       End; { If CurrentEmployeePtr }
  444.     WriteLn;
  445.     If Not Found Then
  446.       Begin
  447.         WriteLn('The employee ',Name,' has quit but could not be deleted from the');
  448.         WriteLn('queue because the name could not be found to exist in the employee queue.');
  449.       End { If Not Found }
  450.     Else
  451.       WriteLn('The employee ',Name,' has quit and was deleted from the employee queue.');
  452.   End;    { EmployeeQuit }
  453.  
  454.  
  455.  
  456. Begin   { ProcessEmployeeModule }
  457.   Command:=ReturnSecondEntry(FileEntry); { determine employee processing command }
  458.   Name:=ReturnThirdEntry(FileEntry);     { determine employee's name }
  459.   If Command='HIRE' Then
  460.     HireEmployee(Name)                   { pass control to specific employee processing procedure }
  461.   Else
  462.     EmployeeQuit(Name);                  { pass control to specific employee processing procedure }
  463. End;    { ProcessEmployeeModule }
  464.  
  465.  
  466.  
  467. Procedure DeleteElementFromTreeModule(Item:ItemString);
  468.  
  469. { This module controls the deletion of an element corresponding to the above
  470.   passed item from the binary search tree.
  471.  
  472.   Note that there are three special cases when deleting an element from a
  473.   binary search tree:
  474.  
  475.            1. Delete an element with no children.
  476.            2. Delete an element with one child.
  477.            3. Delete an element with two children.
  478.  
  479.   This procedure begins by searching for the node that contains the element to
  480.   be deleted from the tree.  If that node has an empty subtree, then that node
  481.   is removed from the tree.  If not, then the content of that node is replaced
  482.   by its predecessor, (or the right most node in its left subtree).  The
  483.   predecessor will always have an empty right subtree.
  484.  
  485.   A special circumstance occurs when the root element is the element to be
  486.   deleted.
  487.  
  488.   Note also that the calling routine must check to see that the passed item
  489.   actually exists in the tree. }
  490.  
  491. Var
  492.   DeletedElementNodePtr:TreeNodePtr;   { a pointer used to point to the deleted element in the binary search tree }
  493.   DeletedElementParentPtr:TreeNodePtr; { a pointer used to point to the deleted element's parent }
  494.  
  495.  
  496.  
  497.   Procedure FindElementToDelete(Var TreeNode,TreeNodeParent:TreeNodePtr);
  498.  
  499.   { This recursive procedure is used to find the element which is to be deleted
  500.     from the tree.  Refernce is saved to the deleted element's parent. }
  501.  
  502.   Begin   { FindElementToDelete }
  503.     { Recursive search for element to be deleted }
  504.     If Item<TreeNode^.ItemName Then
  505.       FindElementToDelete(TreeNode^.Left,TreeNode)
  506.     Else { If Item }
  507.       If Item>TreeNode^.ItemName Then
  508.         FindElementToDelete(TreeNode^.Right,TreeNode)
  509.       Else { end of recursive search }
  510.         Begin { found element to be deleted from tree }
  511.           DeletedElementNodePtr:=TreeNode; {save reference to deleted element's node }
  512.           DeletedElementParentPtr:=TreeNodeParent; { save reference to deleted element's parent }
  513.         End; { Else }
  514.   End;    { FindElementToDelete }
  515.  
  516.  
  517.  
  518.   Procedure PlacePredecessorIntoEmptyNode(TreeNode,TreeNodeParent:TreeNodePtr);
  519.  
  520.   { This recursive procedure is used to determine the immeadiate predecessor to
  521.     the deleted element (which now is an empty tree node) and place the
  522.     predecessor's contents into the deleted element's empty tree node.  It then
  523.     links the predecessor's left child to its parent's right branch.  Note that
  524.     the predecessor's right child must be nil by definition. }
  525.  
  526.   Begin   { PlacePredecessorIntoEmptyNode }
  527.     { recursive search for the right most element in the left subtree }
  528.     If TreeNode^.Right<>Nil Then
  529.       PlacePredecessorIntoEmptyNode(TreeNode^.Right,TreeNode)
  530.     Else
  531.       Begin { found right most element in the left subtree }
  532.         { transfer element contents from predecessor to empty node }
  533.         DeletedElementNodePtr^.ItemName:=TreeNode^.ItemName;
  534.         DeletedElementNodePtr^.ItemQuantity:=TreeNode^.ItemQuantity;
  535.         { dispose of predecessor node and relink its left child to it's parent's right branch }
  536.         TreeNodeParent^.Right:=TreeNode^.Left;
  537.         Dispose(TreeNode);
  538.       End; { Else }
  539.   End;    { PlacePredecessorIntoEmptyNode }
  540.  
  541.  
  542.  
  543. Begin   { DeleteElementFromTreeModule }
  544.   FindElementToDelete(TreeRootPtr,TreeRootPtr);
  545.   If DeletedElementNodePtr=TreeRootPtr Then { special concern since no parent to the root }
  546.     With DeletedElementNodePtr^ Do
  547.       Begin
  548.         If (Left=Nil) And (Right=Nil) Then
  549.           Begin { Special Case One }
  550.             Dispose(DeletedElementNodePtr); { remove root }
  551.             TreeRootPtr:=Nil;          { reset tree root pointer to Nil }
  552.           End { Secial Case One }
  553.         Else
  554.           If Left=Nil Then
  555.             Begin { Special Case Two }
  556.               TreeRootPtr:=Right;      { increment tree root pointer }
  557.               Dispose(DeletedElementNodePtr);
  558.             End { Special Case Two }
  559.           Else
  560.             If Right=Nil Then
  561.               Begin { Special Case Two }
  562.                 TreeRootPtr:=Left;     { increment tree root pointer }
  563.                 Dispose(DeletedElementNodePtr);
  564.               End { Special Case Two }
  565.             Else { Special Case Three }
  566.               PlacePredecessorIntoEmptyNode(DeletedElementNodePtr,DeletedElementParentPtr);
  567.       End { With DeletedElementNodePtr^ }
  568.   Else { deleted element is not tree root }
  569.     With DeletedElementNodePtr^ Do
  570.       Begin
  571.         If (Left=Nil) And (Right=Nil) Then
  572.           Begin { Special Case One }
  573.             { routine to determine which parent field to set to Nil }
  574.             If DeletedElementParentPtr^.Left=DeletedElementNodePtr Then
  575.               DeletedElementParentPtr^.Left:=Nil
  576.             Else
  577.               DeletedElementParentPtr^.Right:=Nil;
  578.             Dispose(DeletedElementNodePtr);
  579.           End { Special Case One }
  580.         Else
  581.           If Left=Nil Then
  582.             Begin { Special Case Two }
  583.               { routine to determine which parent field to relink }
  584.               If DeletedElementParentPtr^.Left=DeletedElementNodePtr Then
  585.                 DeletedElementParentPtr^.Left:=Right
  586.               Else
  587.                 DeletedElementParentPtr^.Right:=Right;
  588.               Dispose(DeletedElementNodePtr);
  589.             End { Special Case Two }
  590.           Else
  591.             If Right=Nil Then
  592.               Begin { Special Case Two }
  593.                 { routine to determine which parent field to relink }
  594.                 If DeletedElementParentPtr^.Left=DeletedElementNodePtr Then
  595.                   DeletedElementParentPtr^.Left:=Left
  596.                 Else
  597.                   DeletedElementParentPtr^.Right:=Left;
  598.                 Dispose(DeletedElementNodePtr);
  599.               End { Special Case Two }
  600.             Else { Special Case Three }
  601.               PlacePredecessorIntoEmptyNode(DeletedElementNodePtr,DeletedElementParentPtr);
  602.       End; { With DeletedElementNodePtr^ }
  603. End;    { DeleteElementFromTreeModule }
  604.  
  605.  
  606.  
  607. Procedure ProcessDailyOrdersModule;
  608.  
  609. { This module controls the processing of all the transactions that have occured
  610.   in the previous 24 hours.  The transactions have previously been placed in a
  611.   particular transaction queue for processing.  The four queues are processed
  612.   in the following order:
  613.  
  614.               1. Insert a new item into the store's inventory
  615.               2. Add a quantity to an existing item
  616.               3. Sell a quantity of an existing item
  617.               4. Remove an item from the store's inventory
  618.  
  619.   Control is passed to a particular procedure within this module inorder to
  620.   process the transaction queues. }
  621.  
  622.  
  623.  
  624.   Procedure PrintTransactionsHandledHeading;
  625.  
  626.   { This procedure prints out the transactions handled heading for the daily
  627.     worklog report. }
  628.  
  629.   Begin   { PrintTransactionsHandledHeading }
  630.     WriteLn;
  631.     WriteLn;
  632.     WriteLn('TRANSACTIONS PROCESSED :');
  633.   End;    { PrintTransactionsHandledHeading }
  634.  
  635.  
  636.  
  637.   Procedure RemoveElementFromQueue(Var HeadPtr,TailPtr,CurrentQueueElement,RemovedQueueElement:QueueElementPtr);
  638.  
  639.   { This procedure removes the queue element from within the passed doubly
  640.     linked transaction queue.  There are four transaction queues which
  641.     correspond to:
  642.  
  643.                 Insert a new item into the store's inventory.
  644.                 Add a quantity to an existing item.
  645.                 Sell a quantity of an existing item.
  646.                 Remove an item from the store's inventory.
  647.  
  648.     Note that this procedure does not simply remove queue elements from the
  649.     front of the passed queue, but will remove queue elements from anywhere
  650.     the current queue pointer happens to be pointing to.  This is necessary,
  651.     for example, when a particular transaction cannot be met and it is
  652.     necessary to keep that transaction on the queue for the next business
  653.     day.
  654.  
  655.     Example queue:
  656.                                    __CurrentQueueElement
  657.                                   |  (after being incremented)
  658.                         ______    v
  659.             __     __  |  __  |  __     __     __     __
  660.            |__|-->|__|-- |__| ->|__|-->|__|-->|__|-->|__|-->Nil
  661.  
  662.     HeadPtr--^             ^--RemovedQueueElement      ^--TailPtr
  663.                               (previous
  664.                                CurrentQueueElement)
  665.  
  666.     Note that there are four special cases when deleting a queue element from
  667.     a particular transaction queue:
  668.  
  669.                 1. Delete last remaining queue element from queue.
  670.                 2. Delete queue element from front of the queue.
  671.                 3. Delete queue element from end of queue.
  672.                 4. Delete queue element from middle of queue.    }
  673.  
  674.   Begin   { RemoveElementFromQueue }
  675.     { Special Case One - Check if delete last remaining queue element from queue }
  676.     If HeadPtr=TailPtr Then
  677.       Begin { delete last remaining queue element from queue }
  678.         HeadPtr:=Nil;
  679.         TailPtr:=Nil;
  680.       End { If HeadPtr }
  681.     Else
  682.       { Special Case Two - Check if delete queue element from front of queue }
  683.       If HeadPtr=CurrentQueueElement Then
  684.         Begin { delete queue element from front of queue }
  685.           CurrentQueueElement^.Back^.Front:=Nil; { release link with queue }
  686.           HeadPtr:=CurrentQueueElement^.Back;    { increment head pointer }
  687.         End { If HeadPtr }
  688.       Else
  689.         { Special Case Three - Check if delete queue element from rear of queue }
  690.         If TailPtr=CurrentQueueElement Then
  691.           Begin { delete queue element from end of queue }
  692.             CurrentQueueElement^.Front^.Back:=Nil; { release link with queue }
  693.             TailPtr:=CurrentQueueElement^.Front;   { de-increment tail pointer }
  694.           End { If TailPtr }
  695.         Else
  696.           { Special Case Four - Delete queue element from middle of queue }
  697.             Begin
  698.               CurrentQueueElement^.Front^.Back:=CurrentQueueElement^.Back;  { relink queue }
  699.               CurrentQueueElement^.Back^.Front:=CurrentQueueElement^.Front; { relink queue }
  700.             End; { Else }
  701.     RemovedQueueElement:=CurrentQueueElement;
  702.     CurrentQueueElement:=CurrentQueueElement^.Back; { increment current queue element pointer }
  703.   End;    { RemoveElementFromQueue }
  704.  
  705.  
  706.  
  707.   Procedure DetermineMailOrderClerk(Var Name:ClerkString);
  708.  
  709.   { This procedure returns the mail order clerk name which is processing the
  710.     current transaction.
  711.  
  712.     Each clerk processes just two transactions during his shift even if one of
  713.     the transactions caused an error.  Also, if a clerk only finishes one
  714.     transaction at the end of the day at the start of the next day the clerk
  715.     finishes the second transaction, unless he quits in between.
  716.  
  717.     If the current clerk has only processed one transaction, the
  718.     ItemsProcessedDuringShift counter is incremented one.  If the current clerk
  719.     Has processed two transactions the the CurrentEmployeePtr is incremented
  720.     in the queue and the counter in the previous employee is reset. }
  721.  
  722.   Begin   { DetermineMailOrderClerk }
  723.     With CurrentEmployeePtr^ Do
  724.       Begin
  725.         Name:=EmployeeName; { return name of processing clerk to calling routine }
  726.         { routine to increment current employee pointer }
  727.         If ItemsProcessedDuringShift=0 Then
  728.           ItemsProcessedDuringShift:=ItemsProcessedDuringShift+1 { increment couter }
  729.         Else
  730.           Begin { increment current employee pointer }
  731.             ItemsProcessedDuringShift:=0; { reset counter }
  732.             CurrentEmployeePtr:=NextEmployee; { increment current employee pointer }
  733.           End; { Else }
  734.       End; { With CurrentEmployeePtr }
  735.   End;    { DetermineMailOrderClerk }
  736.  
  737.  
  738.  
  739.   Function EmptyQueue(QueueHeadPtr:QueueElementPtr):Boolean;
  740.  
  741.   { This function is used to check if the passed queue is empty.  If the queue
  742.     is empty this function returns as true, else it returns as false. }
  743.  
  744.   Begin   { EmptyQueue }
  745.     If QueueHeadPtr=Nil Then
  746.       EmptyQueue:=True
  747.     Else
  748.       EmptyQueue:=False;
  749.   End;    { EmptyQueue }
  750.  
  751.  
  752.  
  753.   Function TreeNode(Item:ItemString):TreeNodePtr;
  754.  
  755.   { This function is used to find the passed item in the binary search tree and
  756.     returns a tree node pointer pointing to the found item.  If the item does
  757.     not exist in the binary tree then this function returns as nil. }
  758.  
  759.   Var
  760.     TempTreeNodePtr:TreeNodePtr;       { a temporary tree node pointer used in traversing a the binary search tree }
  761.     Found:Boolean;                     { a flag used to determine if the passed item exists in the binary search tree }
  762.  
  763.   Begin   { TreeNode }
  764.     Found:=False;                      { initialize flag }
  765.     TempTreeNodePtr:=TreeRootPtr;      { start at the root of the binary search tree }
  766.     While (TempTreeNodePtr<>Nil) And Not Found Do
  767.       With TempTreeNodePtr^ DO
  768.         Begin
  769.           If Item=ItemName Then
  770.             Found:=True                { item is in binary search tree }
  771.           Else
  772.             If Item<ItemName Then
  773.               TempTreeNodePtr:=Left    { follow down left branch of subtree }
  774.             Else
  775.               TempTreeNodePtr:=Right;  { follow down right branch of subtree }
  776.         End; { With TempTreeNodePtr^ }
  777.     If Found Then
  778.       TreeNode:=TempTreeNodePtr        { return a pointer to the found item in the binary search tree }
  779.     Else
  780.       TreeNode:=Nil;                   { item not in binary search tree, return to calling routine as nil }
  781.   End;    { TreeNode }
  782.  
  783.  
  784.  
  785.   Function ItemExist(Item:ItemString):Boolean;
  786.  
  787.   { This function determines if the passed item exists in the binary search
  788.     tree.  If the passed item exists this function returns as true, else it
  789.     returns as false. }
  790.  
  791.   Begin   { ItemExist }
  792.     If TreeNode(Item)<>Nil Then
  793.       ItemExist:=True
  794.     Else
  795.       ItemExist:=False;
  796.   End;    { ItemExist }
  797.  
  798.  
  799.  
  800.   Function QuantityOfItem(Item:ItemString):Integer;
  801.  
  802.   { This function returns to the calling routine the quantity of the above
  803.     passed item that is stored in the binary search tree. }
  804.  
  805.   Var
  806.     TempTreeNodePtr:TreeNodePtr;       { a temporary tree node pointer which points to a node in the binary search tree }
  807.  
  808.   Begin   { QuantityOfItem }
  809.     TempTreeNodePtr:=TreeNode(Item);   { get a pointer to the passed item in the binary search tree }
  810.     QuantityOfItem:=TempTreeNodePtr^.ItemQuantity; { return quantity of item to calling routine }
  811.   End;    { QuantityOfItem }
  812.  
  813.  
  814.  
  815.   Procedure ReviseQuantityInTreeNode(Item:ItemString;Quantity:Integer);
  816.  
  817.   { This procedure is used to revise the quantity of the above passed item that
  818.     which are stored in the binary search tree.  The above passed quantity is
  819.     added to the quantity stored under the particular tree node.  A passed
  820.     positve quantity corresponds to receiving a shipment of stock of the above
  821.     passed item.  A passed negative quantity corresponds to selling some stock
  822.     of the above passed item. }
  823.  
  824.   Var
  825.     TempTreeNodePtr:TreeNodePtr;       { a temporary tree node pointer which points to a node in the binary search tree }
  826.  
  827.   Begin   { ReviseQuantityInTreeNode }
  828.     TempTreeNodePtr:=TreeNode(Item);   { get a pointer to the passed item in the binary search tree }
  829.     TempTreeNodePtr^.ItemQuantity:=TempTreeNodePtr^.ItemQuantity+Quantity; { revise quantity stored in binary search tree }
  830.   End;    { ReviseQuantityInTreeNode }
  831.  
  832.  
  833.  
  834.   Procedure AddNodeToTree(Item:ItemString;Quantity:Integer);
  835.  
  836.   { This procedure is used to add the above passed quantity of the above passed
  837.     new item (node) into the binary search tree.  It should be noted that new
  838.     nodes are always inserted into a binary search tree as leaf nodes.  Note
  839.     also that this procedure does not check to see if the above passed item
  840.     already exists in the binary search tree.  The calling routine should first
  841.     check to see that the passed item does not already exist by using the above
  842.     function ItemExist.
  843.  
  844.     Example binary search tree:
  845.  
  846.                                O  <----TreeRootPtr
  847.                               / \
  848.                             /     \
  849.         a Nil node---->   Nil       O   <----a tree node
  850.                                    /  \
  851.                                  /      \
  852.                                Nil       O  <----NewNode (just inserted)
  853.                                         /  \
  854.                                       /      \
  855.                                     Nil      Nil  }
  856.  
  857.   Type
  858.     DirectionType=(LeftBranch,RightBranch); { an enumerated data type used in helping to determine tree traversing
  859.                                               direction }
  860.  
  861.   Var
  862.     TempTreeNodePtr:TreeNodePtr;       { a temporary tree node pointer used in traversing a the binary search tree }
  863.     TempParentNodePtr:TreeNodePtr;     { a temporary tree node pointer used in pointing to the previous tree node
  864.                                          while traversing the binary search tree }
  865.     Direction:DirectionType;           { a temporary index used in connecting a new tree node to an existant tree node }
  866.     NewNode:TreeNodePtr;               { a pointer to the new tree node }
  867.  
  868.   Begin   { AddNodeToTree }
  869.     TempTreeNodePtr:=TreeRootPtr;      { start at the root of the binary search tree }
  870.     While TempTreeNodePtr<>Nil Do      { search routine to find proper location in tree for new node }
  871.       With TempTreeNodePtr^ DO
  872.         Begin
  873.           If Item<ItemName Then
  874.             Begin { traverse down left subtree }
  875.               TempParentNodePtr:=TempTreeNodePtr; { save reference to previous tree node }
  876.               TempTreeNodePtr:=Left;   { follow down left branch of subtree }
  877.               Direction:=LeftBranch;
  878.             End { If Item }
  879.           Else
  880.             Begin { traverse down right subtree }
  881.               TempParentNodePtr:=TempTreeNodePtr; { save reference to previous tree node }
  882.               TempTreeNodePtr:=Right;  { follow down right branch of subtree }
  883.               Direction:=RightBranch;
  884.             End; { Else }
  885.         End; { With TempTreeNodePtr^ }
  886.     New(NewNode);                      { create a new tree node to insert into the binary search tree }
  887.     With NewNode^ Do
  888.       Begin { initialize routine }
  889.         ItemName:=Item;
  890.         ItemQuantity:=Quantity;
  891.         Left:=Nil;
  892.         Right:=Nil;
  893.       End; { With NewNode^ }
  894.     If TreeRootPtr=Nil Then
  895.       TreeRootPtr:=NewNode
  896.     Else { routine to link new node to parent node }
  897.       If Direction=LeftBranch Then
  898.         TempParentNodePtr^.Left:=NewNode
  899.       Else
  900.         TempParentNodePtr^.Right:=NewNode;
  901.   End;    { AddNodeToTree }
  902.  
  903.  
  904.  
  905.   Procedure AddItemsToInventory;
  906.  
  907.   { This procedure processes the AddItemToInventory queue.  This queue contains
  908.     transactions to add new items to the store's inventory.
  909.  
  910.     This procedure first assigns a mail order clerk to process the transaction.
  911.     It then checks if the new item already exists in the store's inventory.  If
  912.     it does then the appropriate error message is printed.  Otherwise the new
  913.     item is added to the store's inventory with the appropriate message printed. }
  914.  
  915.   Var
  916.     ClerkName:EntryString;               { name of the processing clerk }
  917.     CurrentQueueElement:QueueElementPtr; { a pointer the current queue element being processed in the queue }
  918.     RemovedQueueElement:QueueElementPtr; { a temporary pointer to the removed queue element }
  919.     Quantity:Integer;                    { the number of items to be added to the store's inventory }
  920.     ErrorCode:Integer;                   { an error code returned by the function Val }
  921.  
  922.   Begin   { AddItemsToInventory }
  923.     CurrentQueueElement:=NewItemHeadPtr;
  924.     While Not EmptyQueue(CurrentQueueElement) Do
  925.       Begin
  926.         DetermineMailOrderClerk(ClerkName);
  927.         RemoveElementFromQueue(NewItemHeadPtr,NewItemTailPtr,CurrentQueueElement,RemovedQueueElement);
  928.         If ItemExist(RemovedQueueElement^.ItemName) Then
  929.           Begin { new item already exists in store's inventory }
  930.             Val(RemovedQueueElement^.ItemQuantity,Quantity,ErrorCode); { convert string quantity to an integer quantity }
  931.             ReviseQuantityInTreeNode(RemovedQueueElement^.ItemName,Quantity);
  932.             WriteLn;
  933.             WriteLn(ClerkName,' has found that ',RemovedQueueElement^.ItemName,' already exists in the');
  934.             WriteLn('store`s inventory but has added the ',RemovedQueueElement^.ItemQuantity,' of the item ',
  935.                      RemovedQueueElement^.ItemName);
  936.             WriteLn('to the store`s inventory.');
  937.           End { If ItemExist }
  938.         Else
  939.           Begin { add new item to store's inventory }
  940.             Val(RemovedQueueElement^.ItemQuantity,Quantity,ErrorCode); { convert string quantity to an integer quantity }
  941.             AddNodeToTree(RemovedQueueElement^.ItemName,Quantity);
  942.             WriteLn;
  943.             WriteLn(ClerkName,' has added ',RemovedQueueElement^.ItemQuantity,' of the new item ',
  944.                     RemovedQueueElement^.ItemName,' to the');
  945.             WriteLn('store`s inventory.');
  946.           End; { Else }
  947.         Dispose(RemovedQueueElement);
  948.       End; { While Not EmptyQueue }
  949.   End;    { AddItemsToInventory }
  950.  
  951.  
  952.  
  953.   Procedure AddStockToItems;
  954.  
  955.   { This procedure processes the AddQuantityToItem queue.  This queue contains
  956.     transactions to add quantity of an item to the store's inventory.
  957.  
  958.     This procedure first assigns a mail order clerk to process the transaction.
  959.     It then checks if the new item exists in the store's inventory.  If not
  960.     then the appropriate error message is printed.  Otherwise the additional
  961.     stock is added to the store's inventory with the appropriate message
  962.     printed. }
  963.  
  964.   Var
  965.     ClerkName:EntryString;               { name of the processing clerk }
  966.     CurrentQueueElement:QueueElementPtr; { a pointer the current queue element being processed in the queue }
  967.     RemovedQueueElement:QueueElementPtr; { a temporary pointer to the removed queue element }
  968.     Quantity:Integer;                    { the number of items to be added to the store's inventory }
  969.     ErrorCode:Integer;                   { an error code returned by the function Val }
  970.  
  971.   Begin   { AddStockToItems }
  972.     CurrentQueueElement:=AddQuantityHeadPtr;
  973.     While Not EmptyQueue(CurrentQueueElement) Do
  974.       Begin
  975.         DetermineMailOrderClerk(ClerkName);
  976.         RemoveElementFromQueue(AddQuantityHeadPtr,AddQuantityTailPtr,CurrentQueueElement,RemovedQueueElement);
  977.         If Not ItemExist(RemovedQueueElement^.ItemName) Then
  978.           Begin { item does not exist in store's inventory }
  979.             WriteLn;
  980.             WriteLn(ClerkName,' has found that ',RemovedQueueElement^.ItemName,' does not exist in the');
  981.             WriteLn('store`s inventory and therefore could not add to previous stock.');
  982.           End { If Not ItemExist }
  983.         Else
  984.           Begin { add stock to store's inventory }
  985.             Val(RemovedQueueElement^.ItemQuantity,Quantity,ErrorCode); { convert string quantity to an integer quantity }
  986.             ReviseQuantityInTreeNode(RemovedQueueElement^.ItemName,Quantity);
  987.             WriteLn;
  988.             WriteLn(ClerkName,' has added ',RemovedQueueElement^.ItemQuantity,' more units of the item ',
  989.                     RemovedQueueElement^.ItemName);
  990.             WriteLn('to the store`s inventory.');
  991.           End; { Else }
  992.         Dispose(RemovedQueueElement);
  993.       End; { While Not EmptyQueue }
  994.   End;    { AddStockToItems }
  995.  
  996.  
  997.  
  998.   Procedure SellSomeItemStock;
  999.  
  1000.   { This procedure processes the SellSomeItemStock queue.  This queue contains
  1001.     transactions to sell quantities of an item from the store's inventory.
  1002.  
  1003.     This procedure first assigns a mail order clerk to process the transaction.
  1004.     It then checks if the item exists in the store's inventory.  If item is not
  1005.     in the sore's inventory the transaction is left on the queue and the
  1006.     appropriate message is printed.  If there is not enough of the item in the
  1007.     store's inventory the transaction is again left on the queue and a message
  1008.     printed.  Otherwise the items are removed from the store's inventory and
  1009.     shipped, with the proper message given. }
  1010.  
  1011.   Var
  1012.     ClerkName:EntryString;               { name of the processing clerk }
  1013.     CurrentQueueElement:QueueElementPtr; { a pointer the current queue element being processed in the queue }
  1014.     RemovedQueueElement:QueueElementPtr; { a temporary pointer to the removed queue element }
  1015.     Quantity:Integer;                    { the number of items to be added to the store's inventory }
  1016.     ErrorCode:Integer;                   { an error code returned by the function Val }
  1017.  
  1018.   Begin   { SellSomeItemStock }
  1019.     CurrentQueueElement:=SellQuantityHeadPtr;
  1020.     While Not EmptyQueue(CurrentQueueElement) Do
  1021.       Begin
  1022.         DetermineMailOrderClerk(ClerkName);
  1023.         If Not ItemExist(CurrentQueueElement^.ItemName) Then
  1024.           Begin { item does not yet exist in store's inventory, postpone transaction until next day }
  1025.             WriteLn;
  1026.             WriteLn(ClerkName,' has found that ',CurrentQueueElement^.ItemName,' does not exist in the');
  1027.             WriteLn('in the store`s inventory to sell.  ',ClerkName,' has placed the');
  1028.             WriteLn('transaction back onto the queue for processing tomorrow.');
  1029.             CurrentQueueElement:=CurrentQueueElement^.Back; { increment queue element pointer }
  1030.           End { If Not ItemExist }
  1031.         Else
  1032.           Begin { item exists in store's inventory }
  1033.             Val(CurrentQueueElement^.ItemQuantity,Quantity,ErrorCode); { convert string quantity to an integer quantity }
  1034.             If Quantity>QuantityOfItem(CurrentQueueElement^.ItemName) Then
  1035.               Begin { insufficient stock of item, postpone transaction until next day }
  1036.                 WriteLn;
  1037.                 WriteLn(ClerkName,' has found insufficient inventory of the item ',
  1038.                         CurrentQueueElement^.ItemName);
  1039.                 WriteLn('in the store`s inventory to sell.  ',ClerkName,' has placed the');
  1040.                 WriteLn('transaction back onto the queue for processing tomorrow.');
  1041.                 CurrentQueueElement:=CurrentQueueElement^.Back; { increment queue element pointer }
  1042.               End { If Quantity }
  1043.             Else
  1044.               Begin { sufficient stock of item, perform transaction }
  1045.                 ReviseQuantityInTreeNode(CurrentQueueElement^.ItemName,-1*Quantity);
  1046.                 WriteLn;
  1047.                 WriteLn(ClerkName,' has sold ',CurrentQueueElement^.ItemQuantity,' units of the item ',
  1048.                         CurrentQueueElement^.ItemName);
  1049.                 WriteLn('from the store`s inventory.');
  1050.                 RemoveElementFromQueue(SellQuantityHeadPtr,SellQuantityTailPtr,CurrentQueueElement,RemovedQueueElement);
  1051.                 Dispose(RemovedQueueElement);
  1052.               End; { Else }
  1053.           End; { Else }
  1054.       End; { While Not EmptyQueue }
  1055.   End;    { SellSomeItemStock }
  1056.  
  1057.  
  1058.  
  1059.   Procedure RemoveItemsFromInventory;
  1060.  
  1061.   { This procedure processes the RemoveItemFromInventory queue.  This queue
  1062.     contains transactions to delete items from the store's inventory.
  1063.  
  1064.     This procedure first assigns a mail order clerk to process the transaction.
  1065.     It then checks if the item already exists in the store's inventory.  If not
  1066.     then the appropriate error message is printed.  Otherwise the item is
  1067.     removed from the store's inventory with the appropriate message printed. }
  1068.  
  1069.   Var
  1070.     ClerkName:EntryString;             { name of the processing clerk }
  1071.     CurrentQueueElement:QueueElementPtr; { a pointer the current queue element being processed in the queue }
  1072.     RemovedQueueElement:QueueElementPtr; { a temporary pointer to the removed queue element }
  1073.  
  1074.   Begin   { RemoveItemsFromInventory }
  1075.     CurrentQueueElement:=RemoveItemHeadPtr;
  1076.     While Not EmptyQueue(CurrentQueueElement) Do
  1077.       Begin
  1078.         DetermineMailOrderClerk(ClerkName);
  1079.         RemoveElementFromQueue(RemoveItemHeadPtr,RemoveItemTailPtr,CurrentQueueElement,RemovedQueueElement);
  1080.         If Not ItemExist(RemovedQueueElement^.ItemName) Then
  1081.           Begin { item does not exist in store's inventory }
  1082.             WriteLn;
  1083.             WriteLn(ClerkName,' has found that ',RemovedQueueElement^.ItemName,' does not exist in the');
  1084.             WriteLn('store`s inventory and hence cannot be removed from the store`s inventory.');
  1085.           End { If Not ItemExist }
  1086.         Else
  1087.           Begin { remove item from store's inventory }
  1088.             DeleteElementFromTreeModule(RemovedQueueElement^.ItemName);
  1089.             WriteLn;
  1090.             WriteLn(ClerkName,' has removed the item ',RemovedQueueElement^.ItemName,' from the');
  1091.             WriteLn('store`s inventory.');
  1092.           End; { Else }
  1093.         Dispose(RemovedQueueElement);
  1094.       End; { While Not EmptyQueue }
  1095.   End;    { RemoveItemsFromInventory }
  1096.  
  1097.  
  1098.  
  1099. Begin   { ProcessDailyOrdersModule }
  1100.   PrintTransactionsHandledHeading;
  1101.   AddItemsToInventory;
  1102.   AddStockToItems;
  1103.   SellSomeItemStock;
  1104.   RemoveItemsFromInventory;
  1105.   PrintEmployeeQueue;
  1106.   PrintQueues;
  1107. End;    { ProcessDailyOrdersModule }
  1108.  
  1109.  
  1110.  
  1111. Procedure PrintDailyWorklogHeading(FileEntry:FileEntryString);
  1112.  
  1113. { This procedure prints out the daily worklog heading for the daily worklog
  1114.   report. }
  1115.  
  1116. Var
  1117.   CurrentDay:EntryString;            { a string used to store the current day }
  1118.  
  1119. Begin   { PrintDailyWorklogHeading }
  1120.   CurrentDay:=ReturnThirdEntry(FileEntry);
  1121.   WriteLn;
  1122.   WriteLn;
  1123.   WriteLn('DAILY WORKLOG REPORT FOR DAY ',CurrentDay);
  1124.   WriteLn('------------------------------');
  1125. End;    { PrintDailyWorklogHeading }
  1126.  
  1127.  
  1128.  
  1129. Procedure ReadInputFile;
  1130.  
  1131. { This procedure begins by first reading the entry in the declared file.  The
  1132.   file entry is in the form
  1133.  
  1134.              TransactionCode SecondEntry ThirdEntry
  1135.  
  1136.   The procedure then determines the transaction code that is contained in the
  1137.   file entry.  Possible transaction codes are:
  1138.  
  1139.               'N'    Insert a new item into the store's inventory
  1140.               'A'    Add a quantity to an existing item
  1141.               'S'    Sell a quantity of an existing item
  1142.               'R'    Remove an item from the store's inventory
  1143.               '*'    Add or delete a mail order clerk
  1144.               'X'    End of the business day, process orders
  1145.  
  1146.   This procedure then passes control to the specific procedure required.
  1147.   If none of the above transaction codes were entered in the file entry, the
  1148.   procedure prints an error message stating that a bad transaction code was
  1149.   entered. }
  1150.  
  1151. Var
  1152.   DataFile:Text;                       { Text File }
  1153.   FileEntry:FileEntryString;
  1154.   TransactionCodeEntry:FileEntryString;
  1155.  
  1156. Begin   { ReadInputFile }
  1157.   Assign(DataFile,FILE_NAME);          { assign to a disk file }
  1158.   Reset(DataFile);                     { open the file for reading }
  1159.   Repeat                               { read in the file entries }
  1160.     ReadLn(DataFile,FileEntry);
  1161.     TransactionCodeEntry:=TransactionCode(FileEntry);
  1162.     Case TransactionCodeEntry Of       { pass control to specific procedure }
  1163.       'N' : AddElementToQueue(NewItemHeadPtr,NewItemTailPtr,FileEntry);
  1164.       'A' : AddElementToQueue(AddQuantityHeadPtr,AddQuantityTailPtr,FileEntry);
  1165.       'S' : AddElementToQueue(SellQuantityHeadPtr,SellQuantityTailPtr,FileEntry);
  1166.       'R' : AddElementToQueue(RemoveItemHeadPtr,RemoveItemTailPtr,FileEntry);
  1167.       '*' : ProcessEmployeeModule(FileEntry);
  1168.       'X' : Begin
  1169.               PrintDailyWorklogHeading(FileEntry);
  1170.               ProcessDailyOrdersModule;
  1171.             End;
  1172.     Else                               { improper transaction code encountered }
  1173. (*    WriteLn;
  1174.       WriteLn('Bad transaction code was found in the following file entry:');
  1175.       WriteLn('   ',FileEntry); *)
  1176.     End; { Case TransactionCode(FileEntry) }
  1177.   Until Eof(DataFile);
  1178.   Close(DataFile);                     { close the disk file }
  1179. End;    { ReadInputFile }
  1180.  
  1181.  
  1182.  
  1183. Procedure PrintInventoryModule;
  1184.  
  1185. { This module controls the printing out of the store's inventory in
  1186.   alphabetical order. }
  1187.  
  1188.  
  1189.  
  1190.   Procedure PrintInventoryHeading;
  1191.  
  1192.   { This procedure prints a heading identifying the store inventory list. }
  1193.  
  1194.   Begin   { PrintInventoryHeading }
  1195.     WriteLn;
  1196.     WriteLn;
  1197.     WriteLn;
  1198.     WriteLn('CURRENT MAIL ORDER STORE INVENTORY');
  1199.     WriteLn('----------------------------------');
  1200.     WriteLn;
  1201.     WriteLn('Quantity       Item');
  1202.   End;    { PrintInventoryHeading }
  1203.  
  1204.  
  1205.  
  1206.   Procedure InOrder(TreeNode:TreeNodePtr);
  1207.  
  1208.   { This recursive procedure is used to traverse a binary search tree and print
  1209.     out the node's ItemQuantity and ItemName in an inorder manner. }
  1210.  
  1211.   Begin   { InOrder }
  1212.     If TreeNode<>Nil Then
  1213.       Begin
  1214.         InOrder(TreeNode^.Left);         { make left branch recursive call }
  1215.         WriteLn;
  1216.         WriteLn('  ',TreeNode^.ItemQuantity,'       ',TreeNode^.ItemName);
  1217.         InOrder(TreeNode^.Right);       { make right branch recursive call }
  1218.       End; { If TreeNode }
  1219.   End;    { InOrder }
  1220.  
  1221.  
  1222.  
  1223. Begin   { PrintInventoryModule }
  1224.   PrintInventoryHeading;
  1225.   InOrder(TreeRootPtr);
  1226. End;    { PrintInventoryModule }
  1227.  
  1228.  
  1229.  
  1230. Procedure PrintBinaryTree;
  1231.  
  1232. { This procedure prints out the binary search tree node data representing
  1233.   the tree structure it is stored in.  It calls a recursive inorder traversal
  1234.   procedure 'PrintNodesInorder' that travels down the right most subtree first.
  1235.   This recursive procedure does the actual printing of the binary search
  1236.   tree. }
  1237.  
  1238. Const
  1239.   Offset:Integer=15;                   { column offset used in the printing of each tree level }
  1240.  
  1241. Type
  1242.   ChildType=(Left,Right,Root);         { an enumerated data type used in helping to determine tree node child type }
  1243.  
  1244.  
  1245.  
  1246.   Procedure PrintNodesInorder(Node:TreeNodePtr;Level:Integer;Branch:ChildType);
  1247.  
  1248.   { This recursive procedure is used to print the nodes of a binary search
  1249.     tree.  It traverses the tree using an inorder traversal that goes to the
  1250.     right most subtree first. }
  1251.  
  1252.   Begin   { PrintNodesInorder }
  1253.     If Node=Nil Then                   { nil child node }
  1254.       If Node<>TreeRootPtr Then
  1255.         If Branch=Right Then
  1256.           WriteLn('/':Level*Offset,'Nil') { print right nil child node }
  1257.         Else
  1258.           WriteLn('\':Level*Offset,'Nil') { print left nil child node }
  1259.       Else
  1260.         WriteLn(' ':Level*Offset,'Nil') { print nil root }
  1261.     Else
  1262.       Begin
  1263.         PrintNodesInorder(Node^.Right,Level+1,Right); { traverse right subtree }
  1264.         If Node<>TreeRootPtr Then
  1265.           If Branch=Right Then
  1266.             WriteLn('/':Level*Offset,Node^.ItemName) { print right child node }
  1267.           Else
  1268.             WriteLn('\':Level*Offset,Node^.ItemName) { print left child node }
  1269.         Else
  1270.           WriteLn(' ':Level*Offset,Node^.ItemName); { print root }
  1271.         PrintNodesInorder(Node^.Left,Level+1,Left); { traverse left subtree }
  1272.       End; { Else }
  1273.   End;    { PrintNodesInorder }
  1274.  
  1275.  
  1276.  
  1277. Begin   { PrintBinaryTree }
  1278.   WriteLn;
  1279.   WriteLn;
  1280.   WriteLn('BINARY SEARCH TREE FOLLOWS:');
  1281.   WriteLn('---------------------------');
  1282.   WriteLn;
  1283.   WriteLn;
  1284.   PrintNodesInorder(TreeRootPtr,0,Root);
  1285. End;    { PrintBinaryTree }